package com.crane.common.framework.utils;

import com.crane.common.core.exception.SysException;
import org.springframework.beans.BeanUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @author zhenxing.pi
 */
public final class BeanUtil extends BeanUtils {

    /**
     * 将Bean转换为Map
     *
     * @param obj
     * @param ignoredProps
     * @return
     */
    public static Map<String, Object> asMap(Object obj, String... ignoredProps) {
        return asMap(obj, false, ignoredProps);
    }

    public static Map<String, String> asStringMap(Object obj, String... ignoredProps) {
        return asStringMap(obj, false, ignoredProps);
    }

    public static Map<String, Object> asMap(Object obj, boolean isNull, String... ignoredProps) {
        if (obj == null) {
            return null;
        }
        Map<String, Object> propMap = new HashMap<String, Object>();

        Class<?> actualEditable = obj.getClass();
        List<String> ignoreList = (ignoredProps != null ? Arrays.asList(ignoredProps) : null);

        PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);

        for (PropertyDescriptor targetPd : targetPds) {

            Method readMethod = targetPd.getReadMethod();
            String key = targetPd.getName();
            if (readMethod != null && (ignoreList == null || !ignoreList.contains(key)) && !key.equals("class")) {
                try {
                    Object value = readMethod.invoke(obj);
                    if (!isNull || null != value) {
                        propMap.put(key, value);
                    }
                } catch (Exception e) {
                    throw new RuntimeException("Read property value error, propName=" + targetPd.getName(), e);
                }
            }
        }
        return propMap;
    }

    public static Map<String, String> asStringMap(Object obj, boolean isNull, String... ignoredProps) {
        if (obj == null) {
            return null;
        }
        Map<String, String> propMap = new HashMap<String, String>();

        Class<?> actualEditable = obj.getClass();
        List<String> ignoreList = (ignoredProps != null ? Arrays.asList(ignoredProps) : null);

        PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);

        for (PropertyDescriptor targetPd : targetPds) {

            Method readMethod = targetPd.getReadMethod();
            String key = targetPd.getName();
            if (readMethod != null && (ignoreList == null || !ignoreList.contains(key)) && !key.equals("class")) {
                try {
                    Object value = readMethod.invoke(obj);
                    if (null != value && !String.valueOf(value).equals("")) {
                        propMap.put(key, String.valueOf(value));
                    }
                } catch (Exception e) {
                    throw new RuntimeException("Read property value error, propName=" + targetPd.getName(), e);
                }
            }
        }
        return propMap;
    }

    public static void asBean(Map<String, Object> map, Object obj) {
        try {
            Class<?> actualEditable = obj.getClass();
            PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(actualEditable);
            ;

            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();

                if (map.containsKey(key) && !key.equals("class")) {
                    Object value = map.get(key);
                    // 得到property对应的setter方法
                    Method setter = property.getWriteMethod();
                    setter.invoke(obj, value);
                }
            }

        } catch (Exception e) {
            throw new SysException("transMap2Bean Error", e);
        }
    }

    /**
     * list 复制
     *
     * @param list
     * @param classs
     * @return
     */
    public static <K, T> List<K> copyList(List<T> list, Class<K> classs) {
        List<K> result = new ArrayList<>();
        if (list != null) {
            for (Object bean : list) {
                K javaBean = null;
                try {
                    javaBean = classs.newInstance();
                } catch (InstantiationException | IllegalAccessException e) {
                    e.printStackTrace();
                }
                copyProperties(bean, javaBean);
                result.add(javaBean);
            }

        }
        return result;
    }

}
